Python3.12 のスタンドアロン Lambda 関数を作成しつつ、SAM CLIを学んでみた

Python3.12 のスタンドアロン Lambda 関数を作成しつつ、SAM CLIを学んでみた

Python3.12 のスタンドアロン Lambda 関数を作成しつつ、SAM CLIを学んでみました
Clock Icon2024.11.08

はじめに

こんにちは、アノテーションのなかたです。
今回は、Python3.12 のスタンドアロン Lambda 関数を作成しつつ、SAM CLIを学んでみました。

1. テンプレートからプロジェクトを作成する

Standalone functionクイックテンプレートでは Pythonランタイム がサポートされていない

sam init 時に、 AWS Quick Start application templateStandalone function という、それらしいテンプレートがあったので選択したのですが、dotnet と nodejs しか表示されませんでした。

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Data processing
        3 - Hello World Example with Powertools for AWS Lambda
        4 - Multi-step workflow
        5 - Scheduled task
        6 - Standalone function
        7 - Serverless API
        8 - Infrastructure event management
        9 - Lambda Response Streaming
        10 - Serverless Connector Hello World Example
        11 - Multi-step workflow with Connectors
        12 - GraphQLApi Hello World Example
        13 - Full Stack
        14 - Lambda EFS example
        15 - DynamoDB Example
        16 - Machine Learning
Template: 6

Which runtime would you like to use?
        1 - dotnet8
        2 - dotnet6
        3 - nodejs20.x
        4 - nodejs18.x
        5 - nodejs16.x

Hello World Exampleから API Gateway を削除して対応

前項により、Hello World Example テンプレート から API Gateway を手動削除することで構築してみました。
sam init を実行します。

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Data processing
        3 - Hello World Example with Powertools for AWS Lambda
        4 - Multi-step workflow
        5 - Scheduled task
        6 - Standalone function
        7 - Serverless API
        8 - Infrastructure event management
        9 - Lambda Response Streaming
        10 - Serverless Connector Hello World Example
        11 - Multi-step workflow with Connectors
        12 - GraphQLApi Hello World Example
        13 - Full Stack
        14 - Lambda EFS example
        15 - DynamoDB Example
        16 - Machine Learning
Template: 1

Use the most popular runtime and package type? (python3.12 and zip) [y/N]: y

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: N

Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]: N

Would you like to set Structured Logging in JSON format on your Lambda functions?  [y/N]: y
Structured Logging in JSON format might incur an additional cost. View https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs.html#monitoring-cloudwatchlogs-pricing for more details

Project name [sam-app]: sam-standalone-python

Use the most popular runtime and package type? (python3.12 and zip)

このテンプレートでは、デフォルトで python3.12 が選択されるのでランタイムを変更する必要はありませんでした。
コマンドの実行結果として、以下のようにディレクトリが作成されます。

% tree
.
├── README.md
├── __init__.py
├── events
│   └── event.json
├── hello_world
│   ├── __init__.py
│   ├── app.py
│   └── requirements.txt
├── samconfig.toml
├── template.yaml
└── tests
    ├── __init__.py
    ├── integration
    │   ├── __init__.py
    │   └── test_api_gateway.py
    ├── requirements.txt
    └── unit
        ├── __init__.py
        └── test_handler.py

template.ymlからAPI Gateway 部分を削除

AWS::Serverless::Function の Events が API Gateway に該当します。
Events と Eventsに依存する Outputs 部分を削除します。

template.yml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-standalone-python

  Sample SAM Template for sam-standalone-python

Globals:
  Function:
    Timeout: 3

    LoggingConfig:
      LogFormat: JSON
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.12
      Architectures:
        - x86_64
-      Events:
-        HelloWorld:
-          Type: Api
-          Properties:
-            Path: /hello
-            Method: get

Outputs:
-  HelloWorldApi:
-    Description: API Gateway endpoint URL for Prod stage for Hello World function
-    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: Hello World Lambda Function ARN
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: Implicit IAM Role created for Hello World function
    Value: !GetAtt HelloWorldFunctionRole.Arn

また、デフォルトでは requirements.txt に requests ライブラリが入っています。

requirements.txt
requests

今回は requests ライブラリを使う予定はないので、こちらは削除します。
後に外部ライブラリを用いるため、ファイル自体は残しておきます。

requirements.txt
- requests
requestsライブラリを残した場合

Lambda関数にアップロードされるソースコードはこちらのようになります。
requests ライブラリや依存するライブラリがアップロードされてしまっています。
スクリーンショット 2024-11-08 1.08.00
※Pythonスクリプトは少しだけ変更を加えています

2. ビルドしてデプロイする

sam validate

まず、SAMテンプレートとして構文エラーが存在するか確認します。

% sam validate
/Users/dummy/Documents/Dev/sam_learn/sam-standalone-python/template.yaml is a valid SAM Template

sam build

template.yml から CloudFormation ファイルを作成したり、コードのライブラリの依存関係を解決するコマンドです。

sam build
% sam build                
Starting Build use cache                                                                                                                           
Manifest file is changed (new hash: 3298f13049d19cffaa37ca931dd4d421) or dependency folder (.aws-sam/deps/0feab3f2-3197-4309-8842-6b7be69123cb) is 
missing for (HelloWorldFunction), downloading dependencies and copying/building source                                                             
Building codeuri: /Users/dummy/Documents/Dev/sam_learn/sam-standalone-python/hello_world runtime: python3.12 architecture: x86_64          
functions: HelloWorldFunction                                                                                                                      
 Running PythonPipBuilder:CleanUp                                                                                                                  
 Running PythonPipBuilder:ResolveDependencies                                                                                                      
 Running PythonPipBuilder:CopySource                                                                                                               
 Running PythonPipBuilder:CopySource                                                                                                               

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided
dummy sam-standalone-python % sam local invoke
Invoking app.lambda_handler (python3.12)                                                                                                           
Local image is up-to-date                                                                                                                          
Using local image: public.ecr.aws/lambda/python:3.12-rapid-x86_64.                                                                                 

Mounting /Users/dummy/Documents/Dev/sam_learn/sam-standalone-python/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside    
runtime container                                                                                                                                  
START RequestId: e0560354-063f-4fda-88cd-7da02b0e815f Version: $LATEST
event = {}
END RequestId: 23bfb985-fa17-4310-b17d-a3bb548929b6
REPORT RequestId: 23bfb985-fa17-4310-b17d-a3bb548929b6  Init Duration: 0.13 ms  Duration: 117.81 ms     Billed Duration: 118 ms Memory Size: 128 MBMax Memory Used: 128 MB
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}
dummy sam-standalone-python % sam deploy

                Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-dummy
                A different default S3 bucket can be set in samconfig.toml
                Or by specifying --s3-bucket explicitly.
        Uploading to dummy  572845 / 572845  (100.00%)

        Deploying with following values
        ===============================
        Stack name                   : sam-standalone-python
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-dummy
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles             : {}

Initiating deployment
=====================

        Uploading to 5eb472a6bdc5355e14695bb4e76908e5.template  909 / 909  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------------------
Operation                           LogicalResourceId                   ResourceType                        Replacement                       
---------------------------------------------------------------------------------------------------------------------------------------------
+ Add                               HelloWorldFunctionRole              AWS::IAM::Role                      N/A                               
+ Add                               HelloWorldFunction                  AWS::Lambda::Function               N/A                               
---------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:dummy:changeSet/samcli-deploy1730994357/dummy

Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2024-11-08 00:46:06 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 5.0 seconds)
---------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                      ResourceType                        LogicalResourceId                   ResourceStatusReason              
---------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS                  AWS::CloudFormation::Stack          sam-standalone-python               User Initiated                    
CREATE_IN_PROGRESS                  AWS::IAM::Role                      HelloWorldFunctionRole              -                                 
CREATE_IN_PROGRESS                  AWS::IAM::Role                      HelloWorldFunctionRole              Resource creation Initiated       
CREATE_COMPLETE                     AWS::IAM::Role                      HelloWorldFunctionRole              -                                 
CREATE_IN_PROGRESS                  AWS::Lambda::Function               HelloWorldFunction                  -                                 
CREATE_IN_PROGRESS                  AWS::Lambda::Function               HelloWorldFunction                  Resource creation Initiated       
CREATE_IN_PROGRESS -                AWS::Lambda::Function               HelloWorldFunction                  Eventual consistency check        
CONFIGURATION_COMPLETE                                                                                      initiated                         
CREATE_IN_PROGRESS -                AWS::CloudFormation::Stack          sam-standalone-python               Eventual consistency check        
CONFIGURATION_COMPLETE  

sam deploy

ビルドしたものをAWSにデプロイします。

3. マネジメントコンソールから作成されたリソースを確認する

正常にリソースが作成されていることが CloudFormation からも確認できました。
スクリーンショット 2024-11-08 1.05.22

LambdaのIAMロールはデフォルトで AWSLambdaBasicExecutionRole ロールが指定されるようです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

Lambda関数は以下のようになっていました。
スクリーンショット 2024-11-08 1.28.03
※Pythonスクリプトは少しだけ変更を加えています

デプロイが正常に行われたことを確認できたため、gitでコード管理する場合は、この時点でコミットしておくと良いと思います。

4. boto3 ライブラリを追加してみる

boto3 ライブラリ群をビルドする

requirements.txtboto3 と加えるだけでライブラリを追加できます。

requirements.txt
+ boto3

sam build します。

ビルドされたディレクトリ見ると、boto3 の実行に必要なライブラリ群も追加されたことがわかります。

% tree .aws-sam/build/HelloWorldFunction/ -L 1
.aws-sam/build/HelloWorldFunction/
├── __init__.py
├── app.py
+ ├── boto3
+ ├── boto3-1.35.55.dist-info
+ ├── botocore
+ ├── botocore-1.35.55.dist-info
+ ├── dateutil
+ ├── jmespath
+ ├── jmespath-1.0.1.data
+ ├── jmespath-1.0.1.dist-info
+ ├── python_dateutil-2.9.0.post0.dist-info
├── requirements.txt
+ ├── s3transfer
+ ├── s3transfer-0.10.3.dist-info
+ ├── six-1.16.0.dist-info
+ ├── six.py
+ ├── urllib3
+ └── urllib3-2.2.3.dist-info

15 directories, 4 files

5. ローカルでコードをテスト実行する

新しいライブラリを追加したので、正常に実行されるかどうかテストしたいところです。
SAM CLI では sam local invoke という、ローカルで Lambda 関数のテストができる便利なコマンドが用意されています。
Lambdaのコンテナ環境を起動し、ローカルで擬似的にリクエストをテストします。
こちらを実行することで、テストしてみようと思います。

また、通信を伴う処理となると実行に時間がかかるため、タイムアウト値を上げておきます。

template.yml
...

Globals:
  Function:
-    Timeout: 3
+    Timeout: 15

...

変更を反映するため、sam build しておきます。

% sam build
Starting Build use cache                                                                                                                           
Manifest is not changed for (HelloWorldFunction), running incremental build                                                                        
Building codeuri: /Users/dummy/Documents/Dev/sam_learn/sam-standalone-python/hello_world runtime: python3.12 architecture: x86_64          
functions: HelloWorldFunction                                                                                                                      
 Running PythonPipBuilder:CopySource                                                                                                               
 Running PythonPipBuilder:CopySource                                                                                                               

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

sam local invoke

sam local invoke を実行します。

% sam local invoke
Invoking app.lambda_handler (python3.12)                                                                                                           
Local image is up-to-date                                                                                                                          
Using local image: public.ecr.aws/lambda/python:3.12-rapid-x86_64.                                                                                 

Mounting /Users/dummy/Documents/Dev/sam_learn/sam-standalone-python/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside    
runtime container                                                                                                                                  
START RequestId: 6ddb8a7e-c12d-4a50-bb06-94c857651d42 Version: $LATEST
{"timestamp": "2024-11-07T16:57:26Z", "level": "INFO", "message": "Found credentials in environment variables.", "logger": "botocore.credentials", "requestId": "eb787c0a-a695-4a7e-ac7f-46b0bbce1ac4"}
Tokyo Region Instance IDs: ['i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId', 'i-instanceId']
END RequestId: eb787c0a-a695-4a7e-ac7f-46b0bbce1ac4
REPORT RequestId: eb787c0a-a695-4a7e-ac7f-46b0bbce1ac4  Init Duration: 0.07 ms  Duration: 7142.18 ms    Billed Duration: 7143 ms        Memory Size: 128 MB        Max Memory Used: 128 MB
{"statusCode": 200, "body": "{\"message\": \"Successfully retrieved instance IDs\", \"instanceIds\": [\"i-instanceId\", \"i-instanceId\", \"i-instanceId", \"i-instanceId\", \"i-instanceId\", \"i-instanceId\", \"i-instanceId\", \"i-instanceId\", \"i-instanceId\", \"i-instanceId\", \"i-instanceId\", \"i-instanceId\"]}"}

boto3 によるEC2インスタンスの取得が実行できたことがわかります。

使用したPythonスクリプト

Claude 3.5 Sonnet v1 に書いてもらいました。

import json
import boto3

def lambda_handler(event, context):
    # 東京リージョンのEC2クライアントを作成
    ec2 = boto3.client('ec2', region_name='ap-northeast-1')

    # 東京リージョンのすべてのEC2インスタンス情報を取得
    instances = ec2.describe_instances()

    # インスタンスIDのリストを作成
    instance_ids = []
    for reservation in instances['Reservations']:
        for instance in reservation['Instances']:
            instance_ids.append(instance['InstanceId'])

    # インスタンスIDを表示
    print("Tokyo Region Instance IDs:", instance_ids)

    # Lambda関数の戻り値を作成
    return {
        'statusCode': 200,
        'body': json.dumps({
            'message': 'Successfully retrieved instance IDs',
            'instanceIds': instance_ids
        })
    }

再度デプロイする

再度デプロイを行います。

% sam deploy               

                Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxx
                A different default S3 bucket can be set in samconfig.toml
                Or by specifying --s3-bucket explicitly.
        Uploading to 99fdc22fced05169c7a7d541f467bd72  13323456 / 13323456  (100.00%)

        Deploying with following values
        ===============================
        Stack name                   : sam-standalone-python
        Region                       : ap-northeast-1
        Confirm changeset            : True
        Disable rollback             : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxxxx
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles             : {}

Initiating deployment
=====================

        Uploading to cb1cfad616af3e0ee8b8d7f3263e279c.template  910 / 910  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
---------------------------------------------------------------------------------------------------------------------------------------------
Operation                           LogicalResourceId                   ResourceType                        Replacement                       
---------------------------------------------------------------------------------------------------------------------------------------------
* Modify                            HelloWorldFunction                  AWS::Lambda::Function               False                             
---------------------------------------------------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:xxxxxxxxxx:changeSet/samcli-deployxxxxxxxxxx/a9d596ce-9dc4-4d09-8efe-fa6b51e75b85

Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2024-11-08 02:31:59 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 5.0 seconds)
---------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                      ResourceType                        LogicalResourceId                   ResourceStatusReason              
---------------------------------------------------------------------------------------------------------------------------------------------
UPDATE_IN_PROGRESS                  AWS::CloudFormation::Stack          sam-standalone-python               User Initiated                    
UPDATE_IN_PROGRESS                  AWS::Lambda::Function               HelloWorldFunction                  -                                 
UPDATE_COMPLETE                     AWS::Lambda::Function               HelloWorldFunction                  -                                 
UPDATE_COMPLETE_CLEANUP_IN_PROGRE   AWS::CloudFormation::Stack          sam-standalone-python               -                                 
SS                                                                                                                                            
UPDATE_COMPLETE                     AWS::CloudFormation::Stack          sam-standalone-python               -                                 
---------------------------------------------------------------------------------------------------------------------------------------------

CloudFormation outputs from deployed stack
------------------------------------------------------------------------------------------------------------------------------------------------
Outputs                                                                                                                                        
------------------------------------------------------------------------------------------------------------------------------------------------
Key                 HelloWorldFunctionIamRole                                                                                                  
Description         Implicit IAM Role created for Hello World function                                                                         
Value               arn:aws:iam::xxxxxxxxxx:role/sam-standalone-python-HelloWorldFunctionRole-iHwC7YZ8YQ19                                   

Key                 HelloWorldFunction                                                                                                         
Description         Hello World Lambda Function ARN                                                                                            
Value               arn:aws:lambda:ap-northeast-1:xxxxxxxxxx:function:sam-standalone-python-HelloWorldFunction-Ztao7M9Kyybg                  
------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - sam-standalone-python in ap-northeast-1

無事にデプロイが完了しました。
スクリーンショット 2024-11-08 2.37.00

おわりに

SAM の体験として、構成をyamlファイルとして残しておけるところやローカルでテストが行える点が良かったです。
template.yml に関しては、CloudFormation の理解を深めることでより強力に活かせそうだなと感じました。

参考

https://docs.aws.amazon.com/ja_jp/serverlessrepo/latest/devguide/serverlessrepo-quick-start.html

アノテーション株式会社について

アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.